package ms.jasim.console;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import ms.jacrim.framework.ActiveSolution;
import ms.jacrim.framework.Event;
import ms.spm.IAppContext;

public class JasimClientService extends JasimClient {

	Map<String, JasimAgent> agents;
	ActiveSolution solution;
	ArrayList<Event> events;
	int refreshRate = 2000;
	Thread periodicUpdate;
	private List<JasimClientListener> listeners;
	private Timer refreshTimer;

	public JasimClientService(IAppContext context) throws IOException {
		super(context);
		agents = new HashMap<String, JasimAgent>();
		listeners = new ArrayList<JasimClientListener>();
	}

	public Collection<JasimAgent> updateAgentStatus() throws Exception {

		ArrayList<String> agNames = new ArrayList<String>(agents.size());
		for (String agName : agents.keySet())
			agNames.add(agName);

		JasimAgent agent = null;

		sendCommand("view");

		for (boolean done = false; !done;) {
			String response = readString();

			if (!(done = "DONE".equalsIgnoreCase(response))) {
				if (response.startsWith("AGENT")) {
					String agName = response.substring(6);
					agent = createAgent(agName);
					agent.getStatus().clear();
				} else if (agent != null) {
					agent.getStatus().add(response);
				}
			}
		}
		commandMode();

		return agents.values();
	}

	@Override
	public void connect(String serverAddress, int serverPort) throws Exception {
		super.connect(serverAddress, serverPort);
		refresh();
	}

	@Override
	public void shutdown() {
		super.shutdown();
		refresh();
	}

	@Override
	protected void processCommand(String command, String argument) {
		if ("notify".equalsIgnoreCase(command)) {
			if (refreshTimer == null) {
				refreshTimer = new Timer();
				refreshTimer.schedule(new TimerTask() {
					@Override
					public void run() {
						refreshTimer = null;
						refresh();
					}
				}, 1000);
			}
			else
				System.out.println("Notification arrives, but there exists a scheduled Refresh");
		} else
			super.processCommand(command, argument);
	}

	private JasimAgent createAgent(String name) {
		JasimAgent result = agents.get(name);
		if (result == null) {
			result = new JasimAgent(name);
			agents.put(name, result);
		}
		return result;
	}

	public ActiveSolution getActiveSolution() {
		return solution;
	}

	protected void setActiveSolution(ActiveSolution value) {
		solution = value;
	}
	
	public List<Event> getEvents() {
		return events;
	}

	public void updateActiveSolution() throws Exception {
		if (!Connected())
			setActiveSolution(null);
		else {
			sendCommand("query active_solution");
			ActiveSolution sol = readObject();
			setActiveSolution(sol);
			commandMode();
		}
	}
	
	public void updateEvents() throws Exception {
		if (!Connected()) 
			events = null;
		else {
			sendCommand("query events");
			events = readObject();
			commandMode();
		}
	}

	public void setRefreshRate(int value) {
		refreshRate = value;
	}

	public void startPeriodicUpdate() {
		// if (periodicUpdate == null) {
		// periodicUpdate = new Thread(new Runnable() {
		// @Override
		// public void run() {
		// for (;;) {
		// doPeriodUpdate();
		// try {
		// Thread.sleep(refreshRate);
		// } catch (InterruptedException e) {
		// }
		// }
		// }
		// });
		// periodicUpdate.start();
		// }
	}

	public void stopPeriodicUpdate() {
		if (periodicUpdate != null)
			periodicUpdate.interrupt();
		periodicUpdate = null;
	}

	public void addListener(JasimClientListener listener) {
		listeners.add(listener);
	}

	public void removeListener(JasimClientListener listener) {
		listeners.remove(listener);
	}

	protected void notifyListener() {
		for (JasimClientListener e : listeners)
			e.notifyListener();
	}

	public Collection<JasimAgent> getAgents() {
		return agents.values();
	}

	public void refresh() {
		try {
			System.out.println("Refreshing...");
			if (Connected()) {
				updateActiveSolution();
				updateAgentStatus();
				updateEvents();
			} else {
				agents.clear();
				solution = null;
				events = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			notifyListener();
		}
	}

	public JasimAgent getAgent(String agName) {
		return agents.get(agName);
	}
}
